package com.zxk.util;

import cn.hutool.core.io.FileUtil;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.zxk.constant.ParamConstants;
import com.zxk.constant.PicConstants;
import com.zxk.entity.FindPicResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.UUID;


/**
 * 模糊查询算法工具类(基于OPENCV)
 *
 * @author: 舟小亢
 * @date: 2023-08-06 23:08
 */
public class FuzzyPicUtil {

    private static Logger LOG = LoggerFactory.getLogger(FuzzyPicUtil.class);

    private static String PIC_BMP = ".bmp";


    /**
     * 默认循环找图并点击
     *
     * @param destImagePath
     * @return
     */
    public static boolean findAndClickRandom(WinDef.HWND hwnd_0, WinDef.HWND hwnd_1, String destImagePath) throws Exception {
        return findAndClickRandom(hwnd_0, hwnd_1, destImagePath, ParamConstants.FIND_MAX_TIMES);
    }


    /**
     * 找图并点击附带随机数的图片位置
     *
     * @param destImagePath
     * @return
     */
    public static boolean findAndClickRandom(WinDef.HWND hwnd_0, WinDef.HWND hwnd_1, String destImagePath, int maxTimes) throws Exception {
        // 找图需要用主程序的句柄，截图才能全
        FindPicResult pic = FuzzyPicUtil.findPic(hwnd_0, destImagePath, maxTimes);
        if (!pic.isFinded()) {
            return false;
        }
        // 点击需要用子程序的句柄
        return MouseUtil.lClickRandom(hwnd_1, pic.getPicX(), pic.getPicY());
    }

    /**
     * 找图并点击附带随机数的图片位置
     *
     * @param destImagePath
     * @return
     */
    public static boolean findAndClickRandom(WinDef.HWND hwnd_0, WinDef.HWND hwnd_1, String destImagePath, double sim) throws Exception {
        // 找图需要用主程序的句柄，截图才能全
        FindPicResult pic = FuzzyPicUtil.findPic(hwnd_0, destImagePath, sim);
        if (!pic.isFinded()) {
            return false;
        }
        // 点击需要用子程序的句柄
        return MouseUtil.lClickRandom(hwnd_1, pic.getPicX(), pic.getPicY());
    }

    /**
     * 找图并点击附带随机数的图片位置
     *
     * @param destImagePath
     * @return
     */
    public static boolean findAndClickRandom(WinDef.HWND hwnd_0, WinDef.HWND hwnd_1, String destImagePath, int maxTimes, double sim) throws Exception {
        // 找图需要用主程序的句柄，截图才能全
        FindPicResult pic = FuzzyPicUtil.findPic(hwnd_0, destImagePath, maxTimes, sim);
        if (!pic.isFinded()) {
            return false;
        }
        // 点击需要用子程序的句柄
        return MouseUtil.lClickRandom(hwnd_1, pic.getPicX(), pic.getPicY());
    }


    public static FindPicResult findPic(WinDef.HWND hwnd, String destImagePath) throws Exception {
        return findPic(hwnd, destImagePath, ParamConstants.FIND_MAX_TIMES, ParamConstants.SIMILARITY);
    }

    public static FindPicResult findPic(WinDef.HWND hwnd, String destImagePath, int times) throws Exception {
        return findPic(hwnd, destImagePath, times, ParamConstants.SIMILARITY);
    }

    public static FindPicResult findPic(WinDef.HWND hwnd, String destImagePath, double sim) throws Exception {
        return findPic(hwnd, destImagePath, ParamConstants.FIND_MAX_TIMES, sim);
    }

    /**
     * 循环找单图
     *
     * @return
     */
    public static FindPicResult findPic(WinDef.HWND hwnd, String destImagePath, int times, double sim) throws Exception {
        times = times <= 0 ? ParamConstants.FIND_MAX_TIMES : times;
        String picName = destImagePath.substring(destImagePath.lastIndexOf(File.separator) + 1);
        FindPicResult pic = null;
        LOG.warn("开始找图[{}]!", picName);
        try {
            for (int i = 0; i < times; i++) {
                String srcImagePath = null;
                try {
                    srcImagePath = getHwndPic(hwnd);
                    pic = OpencvUtil.find(srcImagePath, destImagePath, sim);
                    if (pic.isFinded()) {
                        return pic;
                    }
                    LOG.warn("第[{}]次未找到!", i + 1);
                    ThreadUtil.sleep2();
                } finally {
                    // 删除临时图片
                    if (srcImagePath != null) {
                        FileUtil.del(srcImagePath);
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("对比图片错误", e);
            throw e;
        }

        return pic;
    }

    public static FindPicResult findPicM(WinDef.HWND hwnd, String[] destImagePaths) throws Exception {
        return findPicM(hwnd, destImagePaths, ParamConstants.FIND_MAX_TIMES);
    }

    /**
     * 循环找多图，找到返回1，没找到返回0
     *
     * @return
     */
    public static FindPicResult findPicM(WinDef.HWND hwnd, String[] destImagePaths, int times) throws Exception {
        times = times <= 0 ? ParamConstants.FIND_MAX_TIMES : times;
        String picName = "";
        for (String destImagePath : destImagePaths) {
            picName = picName + "|" + destImagePath.substring(destImagePath.lastIndexOf(File.separator) + 1);
        }
        int[] findResult = new int[destImagePaths.length];
        FindPicResult pic = new FindPicResult();
        LOG.warn("开始找图[{}]!", picName);
        try {
            for (int i = 0; i < times; i++) {
                String srcImagePath = getHwndPic(hwnd);
                try {
                    for (int j = 0; j < destImagePaths.length; j++) {
                        pic = OpencvUtil.find(srcImagePath, destImagePaths[j]);
                        if (pic.isFinded() == true) {
                            findResult[j] = 1;
                            pic.setFindResult(findResult);
                            return pic;
                        }
                    }
                    LOG.warn("第[{}]次未找到!", i + 1);
                    ThreadUtil.sleep2();
                } finally {
                    // 删除临时图片
                    FileUtil.del(srcImagePath);
                }
            }
        } catch (Exception e) {
            LOG.error("对比图片错误", e);
            throw e;
        }
        return pic;
    }

    /**
     * 获取指定句柄截图
     *
     * @param hwnd 句柄
     * @return 图片全路径
     */
    public static synchronized String getHwndPic(WinDef.HWND hwnd) {
        // 图片名字：随机数+后缀
        String picName = UUID.randomUUID() + PIC_BMP;
        String picAbsPath = PicConstants.TEMP_PIC_PATH + picName;
        // 获取屏幕尺寸
        WinDef.RECT rect = new WinDef.RECT();
        User32.INSTANCE.GetWindowRect(hwnd, rect);
        int width = rect.right - rect.left;
        int height = rect.bottom - rect.top;
        // 截图
        BufferedImage screenshot = ScreenCapUtil.getScreenshot(new Rectangle(0, 0, width, height), hwnd);
        // 写入文件
        try {
            ImageIO.write(screenshot, "bmp", new File(picAbsPath));
        } catch (IOException e) {
            LOG.error("截屏写入文件失败！", e);
        }
        return picAbsPath;
    }

}
